package lol.clann.minecraft.springboot.api.bukkit.model;

import lol.clann.minecraft.springboot.api.bukkit.constant.ItemFlag;
import lol.clann.minecraft.springboot.api.bukkit.utils.ItemStackUtils;
import lol.clann.minecraft.springboot.api.bukkit.utils.NBTUtils;
import lol.clann.minecraft.springboot.api.context.SpringContext;
import lol.clann.minecraft.springboot.api.model.LazyField;
import lol.clann.minecraft.springboot.bukkit.utils.BukkitUtils;
import lombok.extern.slf4j.Slf4j;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.LeatherArmorMeta;
import org.bukkit.inventory.meta.SkullMeta;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 *
 * @author pyz
 * @date 2019/7/4 11:13 PM
 */
@Slf4j
public class ItemStackBuilder {

    private final ItemStack itemStack;
    private final ItemMeta itemMeta;
    private boolean unbreakable;
    private String localizedName;
    private int hideFlag;
    private final List<String> lores = new ArrayList<>();
    private int repairCost;

    private static final LazyField<ItemStackUtils> itemStackUtils = LazyField.of(() -> SpringContext.getBean(ItemStackUtils.class));
    private static final LazyField<NBTUtils> nbtUtils = LazyField.of(() -> SpringContext.getBean(NBTUtils.class));

    public ItemStack build() {
        itemStack.setItemMeta(itemMeta);
        ItemStack is = itemStackUtils.get().asCraftCopy(itemStack);
        if (lores.size() > 0) {
            itemStackUtils.get().setLore(itemStack, lores);
        }
        if (unbreakable) {
            nbtUtils.get().setValue(itemStackUtils.get().getOrCreateTag(is), "Unbreakable", unbreakable);
        }
        if (hideFlag != 0) {
            nbtUtils.get().setValue(itemStackUtils.get().getOrCreateTag(is), "HideFlags", hideFlag);
        }
        if (localizedName != null) {
            if (BukkitUtils.getBukkitVersionNumber() < 11400) {
                nbtUtils.get().setValue(itemStackUtils.get().getOrCreateDisplayTag(is), "LocName", "{\"text\":\"" + localizedName + "\"}");
            } else {
                nbtUtils.get().setValue(itemStackUtils.get().getOrCreateDisplayTag(is), "LocName", localizedName);
            }
        }
        if (repairCost > 0) {
            nbtUtils.get().setValue(itemStackUtils.get().getOrCreateTag(is), "RepairCost", repairCost);
        }
        return is;
    }

    public ItemStackBuilder(Material material) {
        this.itemStack = new ItemStack(material);
        this.itemMeta = itemStack.getItemMeta();
    }

    public ItemStackBuilder(ItemStack template) {
        this.itemStack = itemStackUtils.get().asCraftCopy(template);
        this.itemMeta = itemStack.getItemMeta();
    }

    public static ItemStackBuilder builder(Material material) {
        return new ItemStackBuilder(material);
    }

    public static ItemStackBuilder builder(ItemStack template) {
        return new ItemStackBuilder(template);
    }

    public ItemStackBuilder amount(int amount) {
        itemStack.setAmount(Math.max(amount, 1));
        return this;
    }

    public ItemStackBuilder durability(short durability) {
        itemStack.setDurability((short) Math.max(durability, 1));
        return this;
    }

    public ItemStackBuilder lore(String lore) {
        if (lore == null) {
            return this;
        }
        lores.add(lore);
        return this;
    }

    public ItemStackBuilder lores(Collection<String> lores) {
        if (lores == null) {
            return this;
        }
        lores.addAll(lores);
        return this;
    }

    public ItemStackBuilder displayName(String displayName) {
        itemMeta.setDisplayName(displayName);
        return this;
    }

    public ItemStackBuilder localizedName(String localizedName) {
        this.localizedName = localizedName;
        return this;
    }

    public ItemStackBuilder unbreakable(boolean unbreakable) {
        this.unbreakable = unbreakable;
        return this;
    }

    public ItemStackBuilder repairCost(int repairCost) {
        this.repairCost = repairCost;
        return this;
    }

    /**
     * 1.8+
     * @param hideFlags
     * @return
     */
    public ItemStackBuilder addItemFlag(ItemFlag hideFlags) {
        this.hideFlag |= this.getBitModifier(hideFlags);
        return this;
    }

    /**
     * 1.8+
     * @param hideFlags
     * @return
     */
    public ItemStackBuilder removeItemFlag(ItemFlag hideFlags) {
        this.hideFlag &= ~this.getBitModifier(hideFlags);
        return this;
    }

    /**
     * 1.8+
     * @param hideFlags
     * @return
     */
    public boolean hasItemFlag(ItemFlag hideFlags) {
        int bitModifier = this.getBitModifier(hideFlags);
        return (this.hideFlag & bitModifier) == bitModifier;
    }

    private byte getBitModifier(ItemFlag hideFlag) {
        return (byte) (1 << hideFlag.ordinal());
    }

    public ItemStackBuilder enchantment(short id, short level, boolean force) {
        Enchantment e = Enchantment.getById(id);
        if (e == null) {
            return this;
        }
        itemMeta.addEnchant(e, level, force);
        return this;
    }

    public ItemStackBuilder enchantment(String name, short level, boolean force) {
        Enchantment e = Enchantment.getByName(name);
        if (e == null) {
            return this;
        }
        itemMeta.addEnchant(e, level, force);
        return this;
    }

    public ItemStackBuilder color(Color color) {
        if (itemMeta instanceof LeatherArmorMeta) {
            ((LeatherArmorMeta) itemMeta).setColor(color);
        }
        return this;
    }

    public ItemStackBuilder skullOwner(String name) {
        if (itemMeta instanceof SkullMeta) {
            ((SkullMeta) itemMeta).setOwner(name);
        }
        return this;
    }

}
